package com.rpframework.module.common.url.explain;

import com.rpframework.module.common.bottom.entity.Jurisdiction;
import com.rpframework.module.common.bottom.entity.enums.RequestType;
import com.rpframework.module.common.url.RequestDescription;
import com.rpframework.utils.ArrayUtils;
import com.rpframework.utils.PackageUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


/**
 * 系统全部URl
 */
@RequestDescription
public class RequestDescriptionExplain {

    private static RequestDescription requestDescription = null;

    public List<Jurisdiction> urlDescribes = null;

    /**
     * 扫描的包
     */
    private String[] packagePaths;

    public RequestDescriptionExplain(String[] packagePaths) {
        super();
        this.packagePaths = packagePaths;
    }

    static {
        requestDescription = RequestDescriptionExplain.class.getAnnotation(RequestDescription.class);
    }

    /**
     * 查找数组
     *
     * @param url 地址
     * @return 唯一个
     */
    public Jurisdiction findByUrl(String url) {
        List<Jurisdiction> urlAll = getUrlAll();
        for (Jurisdiction urlDescribe : urlAll) {
            String[] uris = urlDescribe.getUri();
            for (String uri : uris) {
                if (url.startsWith(uri)) {
                    String urlSon = url.substring(uri.length());
                    List<Jurisdiction> describes = urlDescribe.getUrlDescribes();
                    for (Jurisdiction urlDescribeSon : describes) {
                        String[] urisSon = urlDescribeSon.getUri();
                        for (String uriSon : urisSon) {
                            if (urlSon.startsWith(uriSon)) {
                                return urlDescribe;
                            }
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     * 根据请求类型查找
     *
     * @param requestType 请求类型
     * @return URLs
     */
    public List<Jurisdiction> findByRequestType(RequestType requestType) {
        List<Jurisdiction> urlAllPrimary = getUrlAll();
        List<Jurisdiction> urlAll = new ArrayList<>();
        urlAll.addAll(urlAllPrimary);
        for (int i = 0; i < urlAll.size(); i++) {
            Jurisdiction urlDescribe = urlAll.get(i);
            if (!urlDescribe.getRequestType().equals(requestType)) {
                urlAll.remove(i);
            }
        }
        return urlAll;
    }

    /**
     * 根据请求类型查找 子类型不一致就移除
     *
     * @param requestType 请求类型
     * @return URLs
     */
    public List<Jurisdiction> findByRequestTypeSonRemove(RequestType requestType) {
        List<Jurisdiction> findByRequestType = findByRequestType(requestType);
        for (Jurisdiction urlDescribe : findByRequestType) {
            List<Jurisdiction> urlDescribesSon = urlDescribe.getUrlDescribes();
            for (int i = 0; i < urlDescribesSon.size(); i++) {
                Jurisdiction urlDescribeSon = urlDescribesSon.get(i);
                if (!urlDescribeSon.getRequestType().equals(requestType)) {
                    urlDescribesSon.remove(i);
                }
            }
        }
        return findByRequestType;
    }

    /**
     * 获取所有 URI
     *
     * @param packagePaths 扫描包路径
     * @return URl描述对象
     */
    public List<Jurisdiction> getUrlAll(String... packagePaths) {
        Set<Class<?>> controllerClass = new HashSet<>();
        if (!ArrayUtils.isEmpty(packagePaths)) {
            for (String packagePath : packagePaths) {
                controllerClass.addAll(PackageUtils.scanClasses(packagePath));
            }
        }
        Class<?>[] classes = new Class[controllerClass.size()];
        controllerClass.toArray(classes);
        return getUrlAll(classes);
    }

    /**
     * 获取所有 URI<br>
     * 包路径是配置文件的包路径
     *
     * @return URl描述对象
     */
    public List<Jurisdiction> getUrlAll() {
        return getUrlAll(packagePaths);
    }

    /**
     * 获取所有 URI
     *
     * @param classes 解析类
     * @return URl描述对象
     */
    public List<Jurisdiction> getUrlAll(Class<?>[] classes) {
        if (urlDescribes != null) {
            return urlDescribes;
        }
        List<Jurisdiction> allUrlDescribes = new ArrayList<>();
        for (Class<?> clazz : classes) {
            RequestDescription classDescriptionAnnotation = clazz.getAnnotation(RequestDescription.class);
            RequestMapping classMappingAnnotation = clazz.getAnnotation(RequestMapping.class);

            Jurisdiction classUrlDescribe = analysisUrlDescribe(clazz, classDescriptionAnnotation,
                    classMappingAnnotation, null);

            // 获取方法上注解
            List<Jurisdiction> urlDescribes = new ArrayList<>();
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                RequestMapping methodMappingAnnotation = method.getAnnotation(RequestMapping.class);
                RequestDescription methodDescriptionAnnotation = method.getAnnotation(RequestDescription.class);

                if (methodDescriptionAnnotation != null && methodMappingAnnotation != null) {
                    urlDescribes.add(
                            analysisUrlDescribe(clazz, methodDescriptionAnnotation, methodMappingAnnotation, method));
                }
            }
            if (!urlDescribes.isEmpty()) {
                classUrlDescribe.setUrlDescribes(urlDescribes);
                allUrlDescribes.add(classUrlDescribe);
            }
        }
        urlDescribes = allUrlDescribes;
        return allUrlDescribes;
    }

    /**
     * 重新加载
     */
    public List<Jurisdiction> reload() {
        urlDescribes = null;
        return getUrlAll();
    }

    /**
     * 解析URl描述数据
     *
     * @param clazz                 对象
     * @param descriptionAnnotation 描述注解
     * @param mappingAnnotation     链接地址注解
     * @param method                如果 {@link class} 参数是空的此参数有效
     * @return 地址
     */
    private static Jurisdiction analysisUrlDescribe(Class<?> clazz, RequestDescription descriptionAnnotation,
                                                    RequestMapping mappingAnnotation, Method method) {
        // 获取对象上注解
        String[] classUri = null;
        boolean classCancel = false;
        String classDescription = requestDescription.value();
        RequestType classRequestType = RequestType.PAGE;
        if (mappingAnnotation != null) {

            /*
            老版本
            String[] value = mappingAnnotation.value();
            if (value == null) {
                classUri = new String[]{method.getName()};
            } else {
                classUri = mappingAnnotation.value();
            }*/

            if (method != null) {
                classUri = RequestType.parseUri(method);
            } else {
                classUri = RequestType.parseUri(clazz);
            }
        }
        if (descriptionAnnotation != null) {
            classCancel = descriptionAnnotation.cancel();
            classDescription = descriptionAnnotation.value();
        }
        if (clazz != null) {
            if (clazz.getAnnotation(ResponseBody.class) != null) {
                classRequestType = RequestType.API;
            } else {
                if (method != null) {
                    if (method.getAnnotation(ResponseBody.class) != null) {
                        classRequestType = RequestType.API;
                    }
                }
            }
        } else {
            if (method != null) {
                if (method.getAnnotation(ResponseBody.class) != null) {
                    classRequestType = RequestType.API;
                }
            }
        }
        return new Jurisdiction(classDescription, classUri, classCancel, classRequestType);
    }
}
